const { src, dest, series, parallel, watch } = require('gulp');
const { readVersionConf, CONFIG_PATH } = require('./build/create_version')


// plugins
const inlinesource = require('gulp-inline-source');
const del = require('delete');
const connect = require('gulp-connect');
const proxy = require('http-proxy-middleware');
const changed = require('gulp-changed');
const babel = require('gulp-babel');
const minifyCss = require("gulp-minify-css");
const miniImg = require('gulp-imagemin');
const uglify = require('gulp-uglify');
const fileinclude = require('gulp-file-include')
const minifyHtml = require('gulp-minify-html')
const concat = require('gulp-concat')
const rev = require('gulp-rev');
const gulpIf = require('gulp-if');
const vinylPaths = require('vinyl-paths');
const path = require('path');
const Colors = require('colors')
const preprocess = require('gulp-preprocess')

// 获取版本号
const globalConf = readVersionConf(CONFIG_PATH)

Colors.setTheme({
    cHead: 'magenta',
    cWarning: 'yellow',
    cError: 'red',
    cInfo: ['black', 'bgWhite']
})


const rename = require("gulp-rename");
const revCollector = require('gulp-rev-collector');


// 构建类型
const ENV_TYPE = process.env.NODE_ENV || 'dev'

// 环境判断
function isBuild(){
    return ENV_TYPE === 'build'
}

// 获取环境变量配置
function getEvnConf(){

    const commonConf = {
        APP_NAME: globalConf.APP_NAME,
        APP_VERSION: globalConf.APP_VERSION
    }
    
    const ENV_CONTEXT = {
        
        'dev': {
            NODE_ENV: 'dev',
            API_WHERE: false,
        },
        'build': {
            NODE_ENV: 'build',
            API_WHERE: true,
        },
        'onlineDev': {
            NODE_ENV: 'onlineDev',
            API_WHERE: true,
        }
        
    }

    return Object.assign({}, ENV_CONTEXT[ENV_TYPE], commonConf)
}

const baseOut = './dist';
const baseEntry = './src/';
const jsOut = `${baseOut}/js`;
const cssOut = `${baseOut}/css`;
const htmlOut = `${baseOut}`;
const staticOut = `${baseOut}/`;

const devServe = {

    middleware: () => [
        proxy('/jbfw', {
            target: globalConf.proxy,
            changeOrigin: true
        })
    ]
    
}

const babelConf = {
    presets: ['@babel/env']
}

// 需要打包js文件
const jsPool = [

    'cordova.js',
    'zepto.js',
    'iscroll.js',
    'bingotouch.js',
    
    'plugin/linkplugins.js',//获取用户登录信息
    'plugin/datepicker/datepicker.js',//日历
    'plugin/linkplugins.js',
    'easydialog.js',
    
    //项目封装函数
    '$app.js',
    'app/*.js',//$app 大对象子类合并
    '$ajax.js'//统一封装接口地址
    
];

// 需要打包css文件
const cssPool = [

    'bingotouch.css',
    'plugin/datepicker/datepicker.css',//日历
    'app.css',
    'keyframes.css',
    'loading.css',
    'easydialog.css',//弹框
    'main.css',
    
];

// 构建完整文件路径
function pathPrefix(paths, basePath= + "*.*"){
    return paths.map(path => basePath + path );
}


/**
 * @module css打包
 */
function packCss(){

    const cssPath = `${baseEntry}*.css`

    return src(pathPrefix(cssPool, `${baseEntry}**/`))
           .pipe(changed(cssPath))
           .pipe(concat('all.min.css'))
           .pipe(gulpIf(() =>isBuild(), minifyCss()))
           .pipe(dest(cssOut))
}


/**
 * @module js打包
 */
function packJs(){

    return src(pathPrefix(jsPool, `${baseEntry}**/`))
            .pipe(preprocess({ context: getEvnConf() }))
            .pipe(gulpIf((file) =>{

                // 打包黑名单
                const blackList = [
                    'cordova.js',
                    'zepto.js',
                    'echarts.simple.min.js',
                ]

                const end =  blackList.reduce((prev, next) =>{

                    if(prev){
                        return true
                    }
                    return file.path.indexOf(next) > 0;
                    
                }, false)

                return !end

            }, babel(babelConf)))
            .pipe(concat('all.min.js'))
            .pipe(dest(jsOut))
            .pipe(uglify())
            .pipe(gulpIf(() =>isBuild(), rev()))
            .pipe(gulpIf(() =>isBuild(), dest(jsOut)))
            .pipe(gulpIf(() =>isBuild(), rev.manifest()))
            .pipe(gulpIf(() =>isBuild(), dest(jsOut)))
            
}

/**
 * @module 静态资源
 */
function packStatic(){
    return src('./static/**/**.*')
           .pipe(gulpIf(() =>isBuild(), miniImg()))
           .pipe(dest(staticOut))
}


/**
 * @module 开发服务器
 */
function server(config={}){

    const baseConf = {
        root: baseOut,
        livereload: true,
        host: globalConf.host,
        port: globalConf.port,
        ...devServe
    }

    connect.server({
        ...baseConf,
        ...config
    })
    
}


/**
 * @module 开发服务器重载
 */
function reLoad(){
    return src(baseOut)
           .pipe(connect.reload())
}

/**
 * @module 内联js转换
 */
function toBabel(){
    const inlineJs = `${baseEntry}/html/*/*.js`

    return src(inlineJs)
            .pipe(preprocess({ context: getEvnConf() }))
            .pipe(babel(babelConf))
            .pipe(rename( path => {
                    path.dirname = './'
                }))
            .pipe(dest(baseOut))
}


/**
 * @module html打包
 */
function copyHtml(){
    const htmlTmp = `${baseEntry}html/*/*.html`
    let fileName = ''
    return src(htmlTmp)
            .pipe(fileinclude({
                prefix: '@@',
                basepath: baseEntry + 'html/common',
                indent:false
            }))
            .pipe(changed(htmlTmp))
            .pipe(gulpIf(() => isBuild(), minifyHtml()))
            .pipe(rename( path => {
               path.dirname = './'
            }))
           .pipe(dest(baseOut))
           
}

/**
 * @module 合并html及内联js
 */
function htmlMixJs(){
    const tmp = `${baseOut}/*.html`

    return src(tmp)
            .pipe(preprocess({ context: { NODE_ENV: ENV_TYPE } }))
            .pipe(inlinesource())
            .pipe(dest(baseOut))
            .pipe(vinylPaths((filePath) =>{

                    const fileName = path.format({
                        dir: path.normalize(baseOut),
                        name: path.parse(filePath).name,
                        ext: '.js'
                    })
                    del([fileName])
                    return Promise.resolve()
            }))
        
}

const insetJs = series(toBabel, copyHtml, htmlMixJs)


/**
 * @module 清除原打包文件
 */
function cleanBuildFile(cb){
    del([baseOut], cb)
}

/**
 * @module 构建
 * 打包编译后，重启服务
 */
const build = series(insetJs, parallel(packCss, packJs, packStatic), reLoad, over)

/**
 * @module 热更新
 */
function watchFile(cd){

    watch([baseEntry], cd =>{
        build()
        cd()
    })
  
}

/**
 * @module 混合hash文件
 */
function mixHashJs(){
    return src([baseOut+'/js/*.json', baseOut+'/*.html'])
        .pipe(revCollector())
        .pipe(dest(baseOut)); 
}


/**
 * @module 打包结束提示
 */
function over(cd){
    console.log(">>>>> over <<<<<".cInfo)
    cd()
}



exports.dev = series(cleanBuildFile, parallel(packCss,  packJs, insetJs, packStatic),  parallel(server, watchFile))
exports.build = series(cleanBuildFile, parallel(packCss,  packJs, insetJs, packStatic), mixHashJs, over)
